#include "SypEngine.h"

#ifdef CHECKMEM
#include "mmgr.h"
#endif
namespace Syp
{
SypEngine::~SypEngine()
{
	
}

SypEngine* SypEngine::ge = 0;

SypEngine& SypEngine::getSypEngine()
{
		assert(ge && "Game Engine has not been created");
		return (*ge);
};

Font& SypEngine::getSysFontRef()
{
	return (*system);
}

int SypEngine::realWindowClose()
{
	if(ge->winClose)
	{
	ge->winClose();
	}
	return 0;
}

void SypEngine::setWindowCloseCallback(SYPWindowCloseFunction function)
{
	winClose = function;
}

void SypEngine::loadFromFile(const String& filename, String& contents)
{
	
	InputStream fin;
	InputStream fin2;
    fin.open(filename.c_str());
	char* buf;
	PInt count = 0;
	char tempLine[256] = {0};

	if(!fin.is_open())
	{
		ErrorLogger::getLogger()<<"Error : File : "<<filename <<" not found."<<std::endl;
		return;
	}
	//Get number of lines
	while(!fin.eof())
	{
		fin.getline(tempLine, 256, '\n');
		count++;
	}
	//Start from the top
	fin.close();
	fin2.open(filename.c_str());
	//allocate memory
	buf = new char[count * 256];
	//Get that amount of data until end of file
	fin2.getline(buf,256 * count,'\0');

	
	contents.insert(0, buf, 128 * count );
	contents.resize(contents.find_first_of('\0'));
	ErrorLogger::getLogger()<<"Loaded : "<<contents<<std::endl;

	delete[] buf;
	fin2.close();
}

void SypEngine::createSypEngine()
{
	ge = new SypEngine();
}


SYPThread SypEngine::createThread(SYPThreadFunction function, void *arg)
{

#ifdef GEMULTITHREAD
	return glfwCreateThread(function,arg);
#else
	function(arg);
	return 0;
#endif
}
SYPMutex SypEngine::createMutex()
{
	SYPMutex g = glfwCreateMutex();
	mutexes.push_back(g);
	return g;
}

void SypEngine::destroyMutex(SYPMutex mutex)
{
	glfwDestroyMutex(mutex);
	mutexes.erase( std::find(mutexes.begin(),mutexes.end(),mutex) );
}
void SypEngine::lockMutex(SYPMutex mutex)
{
	#ifdef GEMULTITHREAD
	glfwLockMutex(mutex);
	#endif
}

void SypEngine::unLockMutex(SYPMutex mutex)
{
	#ifdef GEMULTITHREAD
	glfwUnlockMutex(mutex);
	#endif

}



void SypEngine::init(const String& title,int width, int height,bool fullscreen,Font* sys)
{
	assert(ge && "SypEngine has not been created");

	winClose = 0;

	//Init logger
	ErrorLogger::initialise();
	//Init GLFW
    glfwInit();	
	if(fullscreen)
	{
		if(glfwOpenWindow(width,height, 8,8,8,8,24,0,GLFW_FULLSCREEN) == GL_FALSE)
		{
			std::cout<<"Unable to create a OpenGL Window"<<std::endl;
			ErrorLogger::getLogger()<<"Unable to create a OpenGL Window"<<std::endl;
		}
		glfwEnable(GLFW_MOUSE_CURSOR);
	}
	else
	{
		//Create Window
		glfwOpenWindow(width,height, 0,0,0,0,24,0,GLFW_WINDOW);
		
	}	

	glfwSetWindowCloseCallback(realWindowClose);
	glfwSetWindowTitle( title.c_str() );
	glfwSetWindowSizeCallback( Renderer::resizeWindow );

	//No VSYNC
	glfwSwapInterval(0);	
	
	ResourceManager::initialise();
	//Init Renderer
	Renderer::initRenderer(width, height);	
	//Init SceneManager
	SceneManager::initSceneManager();
	//Init FontRegistry
	FontRegistry::initialise();
	//Init InputManager
	InputManager::initialise();
	//Get pointer to Renderer
	rnd = &Renderer::getRenderer();	
	//Init PassRegistry
	PassRegistry::initialise();
	//Init EffectRegistry
	EffectRegistry::initialise();
	//Inits all Core Effects/Passes
	initCorePack();
	

	ErrorLogger::getLogger()<<"Received : R"<<glfwGetWindowParam(GLFW_RED_BITS)<<" G"<<glfwGetWindowParam(GLFW_GREEN_BITS)<<" B"<<glfwGetWindowParam(GLFW_BLUE_BITS)<<" A"<<glfwGetWindowParam(GLFW_ALPHA_BITS)<<" D"<<glfwGetWindowParam(GLFW_DEPTH_BITS)<<std::endl;


	//Initialise System Font
	//If a font is provided, use it
	if(sys)
	{
		system = sys;
	}
	else
	{//else use a default	
	//Make a new font
	system = Font::createFont("SystemFont");
	//Init font to use font.png image,font widths from font.dat and a font color
	system->initFonts("Fonts/FreeSans.ttf",14, 3);		
	}
	
	
	////Read config file
	//String key;
	//InputStream fin;
	//fin.open("config.ini");
	//while(!fin.eof())
	//{
	//	fin>>key;
	//	if(key=="Font")
	//	{
	//		fin>>key;           	
	//	}
	//	else
	//	{
	//		ErrorLogger::getLogger()<<"Error : Font Key is an Unkown Key value.";
	//		assert(false && "Font Key is an Unkown Key value.");
	//	}
	//}
	//fin.close();

	currFrame = glfwGetTime();
	timeDiff = currFrame;
	lastFrame = 0;

	totalElapsed = 0.0f;
	FPS = 0;
	showFPS = 0;
}

float SypEngine::getVersion()
{
	return 0.16f;
}

void SypEngine::releaseSypEngine()
{
	assert(ge && "Game Engine has not been created");
	ge->release();
	delete ge;
	ge = 0;
}

void SypEngine::release()
{		
	FontRegistry::release();
	//Release Input Manager
	InputManager::release();
	//SceneManager requires the use of the Meshes to decrement their reference count b4 deleting MeshInstances.	
	SceneManager::releaseSceneManager();
		//We need the Renderer to unload meshes from gfx card, so we destruct b4 the Renderer
	PassRegistry::release();
	 //We do it b4 Renderer incase there are meshes/textures not released yet and they can be deleted/removed from VRAM with the help of Renderer.
	ResourceManager::release();


	EffectRegistry::release();

//	MaterialManager::release();   
	Renderer::release();	
	//Report undeleted mutexes
	ErrorLogger::getLogger()<<"Number of undestroyed mutexes : "<<static_cast<PInt>(mutexes.size())<<std::endl;
	//close file
	ErrorLogger::release();
	//Close window and terminate GLFW
	glfwTerminate();

}



void SypEngine::run()
{
	rnd->doAdmin();
	//Clear font buffer every frame
	FontRegistry::getRegistry().clearFontBuffers();
	//FPS code
	
	currFrame = glfwGetTime();
	
	timeDiff = currFrame - lastFrame;
	lastFrame = currFrame;

	totalElapsed += static_cast<float>(timeDiff);
	if(totalElapsed >= 1.0f)
	{
		totalElapsed = 0.0f;
		showFPS = FPS;
		FPS = 0;
	}
	else
	{
		++FPS;
	}
	
	//stream<<"FPS "<<showFPS<<" Time "<<currFrame<<"\n TimeDiff "<<timeDiff;
	String FPSTxt = "FPS /c(1 1 0)" + boost::lexical_cast<String>(showFPS) + "/c(0 1 0) Time /c(1 1 0)" + boost::lexical_cast<String>(currFrame) + "\n/c(0 1 0)TimeDiff /c(1 1 0)" + boost::lexical_cast<String>(timeDiff) + "\n/c(0 1 0)Num Polygons /c(1 1 0)" + boost::lexical_cast<String>(Renderer::getRenderer().getNumPolyDrawn());
	//modifies mesh
	system->draw(FPSTxt,10.0f,rnd->getHeight() - 30.0f, 999.0f);
	const MouseState& ms = InputManager::getInputManager().getMouseStateRef();
	FPSTxt =  "MouseX /c(1 1 0)" + boost::lexical_cast<String>(ms.mouseX) + "\n /c(0 1 0)MouseY /c(1 1 0)" + boost::lexical_cast<String>(ms.mouseY);
	system->draw(FPSTxt,400.0f,rnd->getHeight() - 30.0f, 999.0f);
	
	//Sets writing position back to 0, instead of having to delete current string and allocating memory for a new one.
	//stream.seekp(0);
	///FPS code
		
	isOpen = (glfwGetWindowParam(GLFW_OPENED) != 0);
	isActive = glfwGetWindowParam(GLFW_ACTIVE) != 0;

	InputManager::getInputManager().getInput();
}


}
